/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  (C) Copyright 2004, Li Chunqiang (chunqiang_li@c-sky.com)
 *  (C) Copyright 2009, Hu Junshan (junshan_hu@c-sky.com)
 *  (C) Copyright 2009, C-SKY Microsystems Co., Ltd. (www.c-sky.com)
 *
 */

#ifndef __CKCORE_ENTRY_H
#define __CKCORE_ENTRY_H

#include <asm/setup.h>
#include <asm/page.h>

/*
 * Stack layout in 'ret_from_exception':
 *      Below describes the stack layout after initial exception entry.
 *      All traps, interrupts and exceptions will set up the stack frame
 *      in this way before starting processing proper.
 *	This allows access to the syscall arguments in registers r1-r5
 *
 *	 0(sp) - pc
 *	 4(sp) - r1
 *	 8(sp) - syscallr2
 *	 C(sp) - sr
 *	10(sp) - r2
 *	14(sp) - r3
 *	18(sp) - r4
 *	1C(sp) - r5
 *	20(sp) - r6
 *	24(sp) - r7
 *	28(sp) - r8
 *	2C(sp) - r9
 *	30(sp) - r10
 *	34(sp) - r11
 *	38(sp) - r12
 *	3C(sp) - r13
 *	40(sp) - r14
 *	44(sp) - r15
 */


/*
 *      Offsets into the stack to get at save registers.
 */
#define LSAVE_R1         0x4
#define LSAVE_SYSCALLR1  0x8
#define LSAVE_R2         0x10
#define LSAVE_R3         0x14
#define LSAVE_R4         0x18
#define LSAVE_R5         0x1C
#define LSAVE_R6         0x20
#define LSAVE_R7         0x24
#define LSAVE_R8         0x28
#define LSAVE_R9         0x2C
#define LSAVE_R10        0x30
#define LSAVE_R11        0x34
#define LSAVE_R12        0x38
#define LSAVE_R13        0x3C
#define LSAVE_R14        0x40
#define LSAVE_R15        0x44

#define ALLOWINT 	0xffffffbf

#ifdef __ASSEMBLY__


#define SAVE_ALL    save_all
#define RESTORE_ALL restore_all
/*
 *      This code creates the normal kernel pt_regs layout on a trap
 *      or interrupt. The only trick here is that we check whether we
 *      came from supervisor mode before changing stack pointers.
 */

.macro	save_all 
        mtcr    r1, ss2         /* save original r1 */
        mtcr    r2, ss3         /* save original r2 */
		lrw     r1, excepton_stack
		mfcr    r2, epc         /* Get original PC */
		stw     r2, (r1, 0)     /* Save original PC in stack*/
		mfcr    r2, ss2
		stw     r2, (r1, 4)     /* Save original r1 in stack */
		mfcr    r2, ss3
		stw     r2, (r1, 8)     /* Save original r2 in stack */
        mfcr    r1, epsr        /* Get original PSR */
        btsti   r1, 31          /* Check if was supervisor */
        bt      1f
        mtcr    r0, ss1         /* save user stack */
        mfcr    r0, ss0         /* Set kernel stack */
        1:
        subi    r0, 28 
        subi    r0, 32
        stw     r1, (r0, 0)
        stw     r2, (r0, 4)
        stw     r3, (r0, 8)
        stw     r4, (r0, 12)
        stw     r5, (r0, 16)
        stw     r6, (r0, 20)
        stw     r7, (r0, 24)
        stw     r8, (r0, 28)
        stw     r9, (r0, 32)
        stw     r10, (r0, 36)
        stw     r11, (r0, 40)
        stw     r12, (r0, 44)
        stw     r13, (r0, 48)
        stw     r14, (r0, 52)
        stw     r15, (r0, 56)

        subi    r0, 12          /* Make room for PC/PSR/r1 */
		lrw     r2, excepton_stack
		ldw     r1, (r2, 0)     /* Get original PC from stack*/
		stw     r1, (r0, 0)        /* Save PC */
		ldw     r1, (r2, 8)     /* Get syscall r2 from stack*/
		/*
		 * syscallr1->syscallr2;r1->r2
		 * please refer asm/ptrace.h
		 */
		stw     r1, (r0, 8)     /* Save syscall r2 */	
        ldw     r1, (r2, 4)     /* Get syscall r1 from stack*/
        stw     r1, (r0, 4)   	/* Save r1 */
        ldw     r2, (r2, 8)         /* restore original r2 */
.endm

.macro	restore_all
        psrclr	ie              /* Disable interrupt */
        ldw     r2, (r0)        /* Restore PC */
		lrw     r1, excepton_stack
		stw     r2, (r1, 0)     /* Store return PC in stack */
        ldw     r2, (r0, 12)    /* Get saved PSR */
		stw     r2, (r1, 4)     /* Store return PSR in stack */
        ldw     r1, (r0, 4)     /* Get original r1 */
        addi    r0, 16    
        ldm     r2-r15, (r0)    /* Restore registers */       
        addi    r0, 32          /* Increment stack pointer */
        addi    r0, 24 
		mtcr    r3, ss3
		mtcr    r4, ss4
		lrw     r3, excepton_stack
		ldw     r4, (r3, 0)       
		mtcr    r4, epc         /* Set return PC */
		ldw     r4, (r3, 4)
		mtcr    r4, epsr        /* Restore PSR */
        btsti   r4, 31          /* Check if returning to user */
		mfcr    r3, ss3 
		mfcr    r4, ss4
        bt      1f
        mtcr    r0, ss0         /* Save kernel stack*/
        mfcr    r0, ss1         /* Set  user stack */ 
        1:
        rte
.endm

#define SWITCH_STACK_SIZE (15*4)	/* includes return address */

#define SAVE_SWITCH_STACK save_switch_stack
#define RESTORE_SWITCH_STACK restore_switch_stack
#define GET_CURRENT(tmp)

.macro	save_switch_stack
        subi    r0, 32    
        subi    r0, 28

        stw     r1, (r0, 0)
        stw     r2, (r0, 4)
        stw     r3, (r0, 8)
        stw     r4, (r0, 12)
        stw     r5, (r0, 16)
        stw     r6, (r0, 20)
        stw     r7, (r0, 24)
        stw     r8, (r0, 28)
        stw     r9, (r0, 32)
        stw     r10, (r0, 36)
        stw     r11, (r0, 40)
        stw     r12, (r0, 44)
        stw     r13, (r0, 48)
        stw     r14, (r0, 52)
        stw     r15, (r0, 56)
.endm

.macro	restore_switch_stack
        ldm     r1-r15, (r0)     /* Restore all registers */
        addi    r0, 32
        addi    r0, 28
.endm

/*
 * Because kernel don't use FPU and only user program use FPU, we select 
 * coprocessor 15(MMU) when in super-mode. So this macro is called when 
 * CPU enter from user-mode to kernel super-mode except MMU exception.
 */
.macro SET_SMOD_MMU_CP15
#ifdef CONFIG_CPU_HAS_FPU
    cpseti  cp15
#endif
.endm

/*
 * Below, are macros for MMU operating, use them to switch cop, read or write
 * registers of MMU in assemble files. Macro CONFIG_CPU_MMU_CP means MMU in
 * coprocessor.
 */
/* Coprocessor switch to MMU */
.macro SET_CP_MMU 
#ifdef CONFIG_CPU_MMU_CP 
	cpseti  cp15           
#endif 
.endm

/* MMU registers read operators. */
.macro RD_MIR	rx 
#ifdef CONFIG_CPU_MMU_CP 
	cprcr   \rx, cpcr0      
#else 
	mfcr    \rx, cr22
#endif 
.endm

.macro RD_MRR	rx 
#ifdef CONFIG_CPU_MMU_CP 
	cprcr   \rx, cpcr1      
#else 
	mfcr    \rx, cr23
#endif 
.endm

.macro RD_MEL0	rx 
#ifdef CONFIG_CPU_MMU_CP 
	cprcr   \rx, cpcr2      
#else 
	mfcr    \rx, cr24
#endif 
.endm

.macro RD_MEL1	rx 
#ifdef CONFIG_CPU_MMU_CP 
	cprcr   \rx, cpcr3      
#else 
	mfcr    \rx, cr25
#endif 
.endm

.macro RD_MEH	rx 
#ifdef CONFIG_CPU_MMU_CP 
	cprcr   \rx, cpcr4      
#else 
	mfcr    \rx, cr26
#endif 
.endm

.macro RD_MCR	rx 
#ifdef CONFIG_CPU_MMU_CP 
	cprcr   \rx, cpcr5      
#else 
	mfcr    \rx, cr27
#endif 
.endm

.macro RD_MPR	rx 
#ifdef CONFIG_CPU_MMU_CP 
	cprcr   \rx, cpcr6      
#else 
	mfcr    \rx, cr28
#endif 
.endm

.macro RD_MWR	rx 
#ifdef CONFIG_CPU_MMU_CP 
	cprcr   \rx, cpcr7      
#else 
	mfcr    \rx, cr29
#endif 
.endm

.macro RD_MCIR	rx 
#ifdef CONFIG_CPU_MMU_CP 
	cprcr   \rx, cpcr8      
#else 
	mfcr    \rx, cr30
#endif 
.endm

/* MMU registers write operators. */
.macro WR_MIR	rx 
#ifdef CONFIG_CPU_MMU_CP
	cpwcr   \rx, cpcr0         
#else
	mtcr    \rx, cr22
#endif
.endm

.macro WR_MRR	rx 
#ifdef CONFIG_CPU_MMU_CP
	cpwcr   \rx, cpcr1         
#else
	mtcr    \rx, cr23
#endif
.endm

.macro WR_MEL0	rx 
#ifdef CONFIG_CPU_MMU_CP
	cpwcr   \rx, cpcr2         
#else
	mtcr    \rx, cr24
#endif
.endm
.macro WR_MEL1	rx 
#ifdef CONFIG_CPU_MMU_CP
	cpwcr   \rx, cpcr3         
#else
	mtcr    \rx, cr25
#endif
.endm

.macro WR_MEH	rx 
#ifdef CONFIG_CPU_MMU_CP
	cpwcr   \rx, cpcr4         
#else
	mtcr    \rx, cr26
#endif
.endm

.macro WR_MCR	rx 
#ifdef CONFIG_CPU_MMU_CP
	cpwcr   \rx, cpcr5         
#else
	mtcr    \rx, cr27
#endif
.endm

.macro WR_MPR	rx 
#ifdef CONFIG_CPU_MMU_CP
	cpwcr   \rx, cpcr6         
#else
	mtcr    \rx, cr28
#endif
.endm

.macro WR_MWR	rx 
#ifdef CONFIG_CPU_MMU_CP
	cpwcr   \rx, cpcr7         
#else
	mtcr    \rx, cr29
#endif
.endm

.macro WR_MCIR	rx 
#ifdef CONFIG_CPU_MMU_CP
	cpwcr   \rx, cpcr8         
#else
	mtcr    \rx, cr30
#endif
.endm

#else /* C source */

#define STR(X) STR1(X)
#define STR1(X) #X

#define PT_OFF_ORIG_D0	 0x24
#define PT_OFF_FORMATVEC 0x32
#define PT_OFF_SR	 0x2C

#endif


#endif /* __CKCORE_ENTRY_H */
	
